import java.io.BufferedWriter;
import java.io.FileWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import org.omg.CORBA.PUBLIC_MEMBER;

public class CopyOfUtmRwr_Model20140109 extends TopicModel {

	public HashMap<Integer, Integer> wordMap = new HashMap<Integer, Integer>();;
	public HashMap<Integer, Integer> wordMapInv = new HashMap<Integer, Integer>();;

	public HashMap<Integer, Integer> auMap = new HashMap<Integer, Integer>();;
	public HashMap<Integer, Integer> auMapInv = new HashMap<Integer, Integer>();;

	public HashMap<Integer, Integer> usMap = new HashMap<Integer, Integer>();;
	public HashMap<Integer, Integer> usMapInv = new HashMap<Integer, Integer>();;

	public HashMap<Integer, Integer> mMap = new HashMap<Integer, Integer>();;
	public HashMap<Integer, Integer> mMapInv = new HashMap<Integer, Integer>();;

	public HashMap<Integer, Integer> rMap = new HashMap<Integer, Integer>();;
	public HashMap<Integer, Integer> rMapInv = new HashMap<Integer, Integer>();;
	
	public HashMap<Integer, Integer> gTMap = new HashMap<Integer, Integer>();;
	public HashMap<Integer, Integer> gTMapInv = new HashMap<Integer, Integer>();;
	
	public HashMap<Integer, Integer> mTMap = new HashMap<Integer, Integer>();;
	public HashMap<Integer, Integer> mTMapInv = new HashMap<Integer, Integer>();;

	public List<Integer> userList = new ArrayList<Integer>();
	
	public Integer[] moviesId;
	public Integer[] groupsId;
	public Integer[] groupsTId;
	public Integer[] usersId;

	public int[][] movies;
	public int[][] movieUsers;
	public int[][] groupUsers;
	public int[][] groupTMovies;
	public int[][] userMovies;
	public int[][] umRating;
	public int [][]gmRating;
	public double [] gmRank;
	public double [] gmRanktr;
	public int[][] moviesU;
	public int[][] moviesZ;
	public double [][]  pUm;
	public double [][]preGMTrating;
	public double [][] preGMrating;
	public double [][] gmTrating;
	public int[][] nZW;
	public int[] nZ;
	public int[][] nMZ;
	public int[] nM;
	public double [][]nUZ;
	public double [] nU;
	public double [][]nGZ;
	public double [] nG;

	public double[][] npUZ;
	public double[][] npMZ;
	public double[][] npGZ;
	public double [][] sGM;
	public double[][] sMU;
	public double [][] sUG;
	public double [][] sMUG;
	public double [][] sGG;

	public int M;
	public int W;
	public int Z;
	public int G;
	public int U;
	public int Ug;
	public int Um;
	public int Mu;
	public int GT;
	public int MT;
	


	public double beta;
	public double alpha;
	public List<Integer> movieList = new ArrayList<Integer>();
	public List<Integer> movieTList;

	public CopyOfUtmRwr_Model20140109(int z, double a, double b) {
		alpha = a;
		beta = b;
		Z = z;
	}

	@Override
	public void initialize() {
		System.out.println("Initializing...");
		Random r = new Random();

		moviesZ = new int[M][];
		nZW = new int[Z][W];
		nZ = new int[Z];
		nMZ = new int[M][Z];
		nM = new int[M];
		nU= new double[U];
		nUZ=new double[U][Z];
		nG= new double[G];
		nGZ=new double[G][Z];
		
		npUZ = new double[U][Z]; // distributions of topics over users
		npMZ = new double[M][Z];// distributions of topics over movies
		npGZ = new double[G][Z];
		sGM= new double [G][M];
		sMU= new double [M][U];
		sUG= new double [U][G];
		sMUG= new double [M][G];
		pUm= new double [U][M];
		gmRank= new double [G+M];
		gmRanktr= new double [G+M];
		preGMTrating=new double [GT][MT];
		preGMrating= new double [G][MT];
		gmTrating= new double [GT][MT];

		for (int m = 0; m < M; m++) {
			moviesZ[m] = new int[movies[m].length];

			for (int n = 0; n < movies[m].length; n++) {
				int w = movies[m][n];

				int z = r.nextInt(this.Z); // select random z value in {0...Z-1}
				moviesZ[m][n] = z;

				// update counts
				nZW[z][w] += 1;
				nZ[z] += 1;
				nMZ[m][z] += 1;
				nM[m] += 1;
			}
		}
	}

	@Override
	public void doSampling() {
		for (int m = 0; m < M; m++) {
			for (int n = 0; n < movies[m].length; n++) {
				sample(m, n);
			}
		}
		//likelihood();
	}

	public void sample(int m, int n) {
		int w = movies[m][n];
		int topic = moviesZ[m][n];

		// decrement counts
		nZ[topic] -= 1;
		nZW[topic][w] -= 1;
		nMZ[m][topic] -= 1;
		nM[m] -= 1;

		// sample new value for topic

		double pTotal = 0.0;
		double[] p = new double[Z];

		for (int z = 0; z < Z; z++) {
			p[z] = (nZW[z][w] + beta) / (nZ[z] + W * beta)
					* (nMZ[m][z] + alpha);

			pTotal += p[z];
		}

		Random r = new Random();
		double e = r.nextDouble() * pTotal;

		double f = 0;
		for (int z = 0; z < Z; z++) {
			f += p[z];

			if (f > e) {
				topic = z;
				break;
			}
		}
		// increment counts

		nZ[topic] += 1;
		nZW[topic][w] += 1;
		nMZ[m][topic] += 1;
		nM[m] += 1;

		// set new assignments

		moviesZ[m][n] = topic;

	}

	public boolean interrupt(double[] pre, double[] cur){
		double max = 0;
		for(int i=0;i<pre.length;i++){
			max = Math.max(max, Math.abs(pre[i]-cur[i])/pre[i]);
		}
		return max<=0.01;
	}
	
	public void rATM_unRWR(){
		
		// distributions of topics over movies
		for (int m = 0; m < M; m++) {
			for (int z = 0; z < Z; z++) {
				npMZ[m][z] = (nMZ[m][z] + beta) / (nM[m] + Z * beta); 

			}
			
		}
			

		// distributions of topics over users by counting
				for (int u = 0; u < U; u++) {
					     int userId=usersId[u];
					     int userInv=auMap.get(userId);
					for (int z = 0; z < Z; z++) {
						nUZ[userInv][z] = 0;
						nU[userInv] = 0;
						for (int mu = 0; mu < userMovies[u].length; mu++) {
							double sumRating = 0;
							int movieInv=userMovies[u][mu];
							int movieId=mMapInv.get(movieInv);
							int movieItr=movieList.indexOf(movieId);
							for (int um = 0; um < movieUsers[movieItr].length; um++) {
								int uInv=movieUsers[movieItr][um];
								sumRating = sumRating + umRating[uInv][movieInv];
							}
							nUZ[userInv][z] = nUZ[userInv][z] + (umRating[userInv][movieInv] / sumRating)
									* nMZ[movieInv][z];
							nU[userInv] = nU[userInv] + (umRating[userInv][movieInv] / sumRating) * nM[movieInv];
						}
						npUZ[userInv][z] = (nUZ[userInv][z] +beta) / (nU[userInv]+Z*beta);
					}
					//System.out.println(u+"0000000000000000");	
				}
			
				// distributions of topics over groups
				double  sumUm;
				for (int g = 0; g < G; g++) {
					sumUm = 0;
					for (int u = 0; u < groupUsers[g].length; u++) {
						sumUm = sumUm + userMovies[u].length;
					}
					
					for (int z = 0; z < Z; z++) {
						npGZ[g][z]=0;
						for (int u = 0; u < groupUsers[g].length; u++) {
							int userid=groupUsers[g][u];
							int index = userList.indexOf(userid);
							npGZ[g][z] = npGZ[g][z] + npUZ[auMap.get(userid)][z] * userMovies[index].length/sumUm ;
						}
					}
					
			    }
//				for (int i=0; i<npUZ.length; i++){
//					for(int j=0; j<npUZ[i].length; j++){
//						System.out.print(npUZ[i][j]+" ");
//					}
//					System.out.println();
//					System.out.println();
//				}
				for (int i=0; i<npGZ.length; i++){
					for(int j=0; j<npGZ[i].length; j++){
						System.out.print(npGZ[i][j]+" ");
					}
					System.out.println();
					System.out.println();
				}
			System.exit(0);
				
					
		// similarity of groups and movies
				for(int g=0;g<G; g++){
					for(int m=0; m<M; m++){
						sGM[g][m]=0;
						double pgt=0;
						double pmt=0;
						for (int z=0; z<Z; z++){
							sGM[g][m] = sGM[g][m] + npMZ[m][z] * npGZ[g][z];
							pmt = pmt + npMZ[m][z] * npMZ[m][z];
							pgt = pgt + npGZ[g][z] * npGZ[g][z];	
						}
						pmt=Math.sqrt(pmt);
						pgt=Math.sqrt(pgt);
						
						sGM[g][m]=sGM[g][m]/(pmt*pgt);
					}
				}
				
    // similarity of movies and users
		for (int m = 0; m < M; m++) {
			for (int u = 0; u < U; u++) {
				sMU[m][u] = 0;
				double put = 0;
				double pmt = 0;
				for (int z = 0; z < Z; z++) {
					sMU[m][u] = sMU[m][u] + npUZ[u][z] * npMZ[m][z];
					put = put + npUZ[u][z] * npUZ[u][z];
					pmt = pmt + npMZ[m][z] * npMZ[m][z];
				}
				put = Math.sqrt(put);
				pmt = Math.sqrt(pmt);
				sMU[m][u] = sMU[m][u] / (put * pmt);
			}
		}
			// similarity of users and groups
		for (int u=0;u<U; u++){
			for (int g=0; g<G; g++){
				sUG[u][g]=0;
				double pgt = 0;
				double put = 0;
				for (int z=0; z<Z; z++){
					sUG[u][g] = sUG[u][g] + npGZ[g][z] * npUZ[u][z];
					pgt = pgt + npGZ[g][z] * npGZ[g][z];
					put = put + npUZ[u][z] * npUZ[u][z];
				}
				pgt = Math.sqrt(pgt);
				put = Math.sqrt(put);
				sUG[u][g] = sUG[u][g]/(pgt*put);
				
			}
		}
		
		// movie-user-group
		for (int m=0; m<M; m++){
			for(int g=0; g<G; g++){
				sMUG[m][g]=0;
				for (int u=0; u<U; u++){
					
					sMUG[m][g]=sMUG[m][g]+sMU[m][u]*sUG[u][g];
				}	
			}
		}	
		for (int i=0; i<npGZ.length; i++){
			for(int j=0; j<npGZ[i].length; j++){
				System.out.print(npGZ[i][j]+" ");
			}
			System.out.println();
			System.out.println();
		}
	System.exit(0);
		
		// random walk with restart
				double[][] sGG = new double[G + M][G + M]; // transition matrix
				double[] sgm = new double[G + M]; // random matrix
		
		for(int i=0; i<G; i++){
			for (int j = 0; j < M; j++) {
				sGG[i][i] = 0;
				sGG[i][G + j] = sGM[i][j];
				sGG[G + j][i] = sMUG[j][i];
				sGG[G + j][G + j] = 0;
			}
		}
		
		// normalize the transition matrix
				for (int j = 0; j < (G + M); j++) {
					double sumsGG = 0;
					for (int i = 0; i < (G + M); i++) {
						sumsGG = sumsGG + sGG[i][j];

					}
					for (int i = 0; i < (G + M); i++) {
						sGG[i][j] = sGG[i][j] / sumsGG;
					}	
				}
				for (int i=0; i<(G+M); i++){
					for(int j=0; j<(G+M); j++){
						System.out.print(sGG[i][j]+" 88888888888888");
					}
					System.out.println();
				}
				// 初始化随机矩阵
				  Random f = new Random();
				for (int Urwr = 0; Urwr < (G + M); Urwr++) {
					sgm[Urwr] = f.nextDouble(); // random matrix
				}
				
				double[][] ss = new double[10][G];
				int col=0;
				double[] temp;
				
				for (int g = 0; g < G; g++) {
					temp = new double[G+M];
					for (int iter = 0; interrupt(sgm, temp) && iter < 100; iter++) {
						for (int i = 0; i < (G + M); i++) {
							for (int j = 0; j < (G + M); j++) {
								temp[i] +=  sGG[i][j] * sgm[j];
							}
							temp[i] = 0.95*temp[i]+0.05*(g==i?1:0);
						}
						sgm = temp;
					}
					Arrays.sort(sgm,0,G);
					for (int i=0; i<10; i++){
						ss[i][col]=sgm[i];
					}
					col++;
					System.out.println(g+"99999999999999999999");
				}
//				System.out.println("-------------ss[][]:--------------");
//				for(int i=0;i<10;i++){
//					for(int j=0;j<G+M;j++){
//						System.out.print(ss[i][j]+" ");
//					}
//					System.out.println();
//				}
				// 正则化相似性矩阵
				for (int j=0; j<G; j++){
					double sumcol=0;
					for (int i=0; i<10; i++){
						sumcol=sumcol+ss[i][j];	
					}
					for (int i=0; i<10; i++){
						ss[i][j]=ss[i][j]/sumcol;
					}
				}
				
				
				//predicting rating of groups
				for (int g = 0; g < G; g++) { 
					int umnum = 0;
					for (int m = 0; m < MT; m++) { 
						preGMrating[g][m] =0;
						for (int u = 0; u < groupUsers[g].length; u++) {
							umnum = umnum + userMovies[u].length;
						}
						for (int u = 0; u < groupUsers[g].length; u++) {
							preGMrating[g][m] = preGMrating[g][m]
									+ userMovies[u].length / umnum * umRating[u][m];
						}

					}
				}
				// predicting rating of groupT
				for (int g = 0; g < GT; g++) {
					for (int m = 0; m < MT; m++) {
						preGMTrating[g][m] =0;
						for (int i = 0; i < 10; i++) {
							preGMTrating[g][m] = preGMTrating[g][m] + ss[i][g] * preGMrating[i][m];
						}
						System.out.println(preGMTrating[g][m]);
					}
				}
				// MAE
				double mae=0;
				for (int g = 0; g < GT; g++ ){
					for (int m = 0; m < MT; m++){
						double i= preGMTrating[g][m]- gmRating[g][m];
						mae  = mae + Math.abs(i);
					} 
				}
				System.out.println (mae +"mae");
	}

	
	public void writeOutput(String filename) throws Exception {
		FileWriter fw = new FileWriter("AT.assign");
		BufferedWriter bw = new BufferedWriter(fw);

		for (int m = 0; m < M; m++) {
			int movieId = moviesId[m];
			for (int n = 0; n < movies[m].length; n++) {
				int word = wordMapInv.get(movies[m][n]);
	
				bw.write(movieId + "\t" + word );
				bw.newLine();
			}
		}

		bw.close();
		fw.close();
		rATM_unRWR();
	}

	@Override
	public void readDocs(String filename) throws Exception {
		System.out.println("Reading input...");
		try {
			Class.forName("com.mysql.jdbc.Driver"); // 加载MYSQL JDBC驱动程序

			System.out.println("Success loading Mysql Driver!");
		} catch (Exception e) {
			System.out.print("Error loading Mysql Driver!");
			e.printStackTrace();
		}

		try {
			Connection connect = DriverManager.getConnection(
					"jdbc:mysql://localhost:3306/rs_new_small_group", "admin",
					"123");
			// 连接URL为 jdbc:mysql//服务器地址/数据库名 ，后面的2个参数分别是登陆用户名和密码
			Connection testconnect = DriverManager.getConnection(
					"jdbc:mysql://localhost:3306/rs_new_check_group", "admin",
					"123");
			// 连接URL为 jdbc:mysql//服务器地址/数据库名 ，后面的2个参数分别是登陆用户名和密码

			System.out.println("Success connect Mysql server!");
			
			// ATM movie-users
			Statement stmt = connect.createStatement();
			String str = "select movieid from movie";
			ResultSet rs = stmt.executeQuery(str);
			while (rs.next()) {

				int movieId = Integer.parseInt(rs.getString("movieid"));
				//System.out.println(movieId);
				movieList.add(movieId);
			}

			M = movieList.size();
			movies = new int[M][];
			movieUsers = new int[M][];
			moviesId = movieList.toArray(new Integer[0]);
			for (int m = 0; m < moviesId.length; m++) {
				int movieId = moviesId[m];
				//System.out.println("Loading doc: " + movieId + " Progress: "
					//	+ m + "/" + moviesId.length);
				ResultSet rs2 = stmt
						.executeQuery("select userid from user_movie where movieid="
								+ movieId);
				int MusCnt = 0;
				while (rs2.next()) {
					MusCnt++;
				}
				movieUsers[m] = new int[MusCnt];
				for (int na = MusCnt - 1; rs2.previous(); na--) {
					int userId = Integer.parseInt(rs2.getString("userid"));
					int key = auMap.size();
					if (!auMap.containsKey(userId)) {
						auMap.put(userId, new Integer(key));
						auMapInv.put(new Integer(key), userId);
					} else {
						key = auMap.get(userId).intValue();
					}
					movieUsers[m][na] = key;
				}
				ResultSet rs3 = stmt
						.executeQuery("select wordid from movie_word where movieid="
								+ movieId);

				int wCnt = 0;
				while (rs3.next()) {
					wCnt++;
				}
				movies[m] = new int[wCnt];
				for (int wn = wCnt - 1; rs3.previous(); wn--) {
					int word = Integer.parseInt(rs3.getString("wordid"));
					int key = wordMap.size();
					if (!wordMap.containsKey(word)) {
						wordMap.put(word, new Integer(key));
						wordMapInv.put(new Integer(key), word);
					} else {
						key = ((Integer) wordMap.get(word)).intValue();

					}
					movies[m][wn] = key;
				}
			}
			U = auMap.size();

			// 统计group-users 信息

			Statement stmtg = connect.createStatement();// g
			String strg = "select householdid from household ";// g
			ResultSet rsg = stmtg.executeQuery(strg); // g
			List<Integer> groupList = new ArrayList<Integer>();// g

			while (rsg.next()) {

				int groupId = Integer.parseInt(rsg.getString("householdid"));
				//System.out.println(groupId);
				groupList.add(groupId);
			}

			G = groupList.size();
			groupUsers = new int[G][];
			groupsId = groupList.toArray(new Integer[0]);// put the array to the
															// 数组

			for (int g = 0; g < groupsId.length; g++) {
				int groupId = groupsId[g];
				//System.out.println("Loading group: " + groupId + " Progress: "
						//+ g + "/" + groupsId.length);
				ResultSet rsg2 = stmtg
						.executeQuery("select userid from household_user where householdid="
								+ groupId);
				int usCnt = 0;
				while (rsg2.next()) {
					usCnt++;
				}

				groupUsers[g] = new int[usCnt];
				for (int nu = usCnt - 1; rsg2.previous(); nu--) {
					int usId = Integer.parseInt(rsg2.getString("userid"));
					int key = usMap.size();
					if (!usMap.containsKey(usId)) {
						usMap.put(usId, new Integer(key));
						usMapInv.put(new Integer(key), usId);
					} else {
						key = usMap.get(usId).intValue();
					}
					groupUsers[g][nu] = usId;//20140109
				}

			}
			System.out.println("groupUsers---------------");
			for(int i=0;i<groupUsers.length;i++){
				for(int j=0;j<groupUsers[i].length;j++){
					System.out.print(groupUsers[i][j]+" ");
				}
				System.out.println("groupUsers---------------");
			}
			 // 统计user-movie 信息
			Statement stmtu = connect.createStatement();
			String stru = "select userid from user";
			ResultSet rsu = stmtu.executeQuery(stru);
			while (rsu.next()) {
				int userId = Integer.parseInt(rsu.getString("userid"));
				//System.out.println(userId);
				userList.add(userId);
			}
			Um = userList.size();
			userMovies = new int[Um][];
			usersId = userList.toArray(new Integer[0]);
			for (int u = 0; u < usersId.length; u++) {
				int userId = usersId[u];
				// System.out.println("Loading user: " + userId + " Progress: "
				// + u + "/" + usersId.length);
				ResultSet rsu2 = stmtu
						.executeQuery("select movieid from user_movie where userid="
								+ userId);
				int mCnt = 0;
				while (rsu2.next()) {
					mCnt++;
				}
				userMovies[u] = new int[mCnt];
				for (int nm = mCnt - 1; rsu2.previous(); nm--) {
					int mId = Integer.parseInt(rsu2.getString("movieid"));
					int key = mMap.size();
					if (!mMap.containsKey(mId)) {
						mMap.put(mId, new Integer(key));
						mMapInv.put(new Integer(key), mId);
					} else {
						key = mMap.get(mId).intValue();
					}
					userMovies[u][nm] = key;
				}

			}

			// user-movie-rating
			umRating = new int[U][M];
			Statement stmtumr = connect.createStatement();
			String strumr = "select * from user_movie";
			ResultSet rsumr = stmtumr.executeQuery(strumr);
			while (rsumr.next()) {
				int userId = Integer.parseInt(rsumr.getString("userid"));
				int movieid = Integer.parseInt(rsumr.getString("movieid"));
				int rating = Integer.parseInt(rsumr.getString("value"));
				Integer uInv = auMap.get(userId);

				if (uInv == null) {

				} else {
					int mInv = mMap.get(movieid);
					try{
					umRating[uInv][mInv] = rating;
					}
					catch(Exception e){
						System.out.println("----------------------");
						System.out.println(uInv);
						System.out.println(mInv);
						System.out.println("----------------------");
						System.exit(1);
					}
				}

			}
			// test loading GT
						Statement stmtTg = connect.createStatement();
						String strTg = "select householdid from household";
						ResultSet rsTg = stmtTg.executeQuery(strTg);
						List<Integer> groupTList = new ArrayList<Integer>();
						while (rsTg.next()) {
							int groupTId = Integer.parseInt(rsTg.getString("householdid"));
							//System.out.println(groupTId);
							gTMap.put(groupTId, groupTList.size());
							gTMapInv.put(groupTList.size(), groupTId);
							groupTList.add(groupTId);
						}
						GT = groupTList.size();
						
				
						
						
						// test loading MT
						Statement stmtTm = connect.createStatement();
						String strTm = "select movieid from movie";
						ResultSet rsTm = stmtTm.executeQuery(strTm);
						movieTList = new ArrayList<Integer>();
						while (rsTm.next()) {
							int movieTId = Integer.parseInt(rsTm.getString("movieid"));
							//System.out.println(movieTId);
							mTMap.put(movieTId, movieTList.size());
							mTMapInv.put(movieTList.size(), movieTId);
							movieTList.add(movieTId);
						}
						MT = movieTList.size();
						
						
						// group-movie-rating
						gmRating = new int[GT][MT];
						Statement stmtumrT = connect.createStatement();
						String strumrT = "select * from house_movie";
						ResultSet rsumrT = stmtumrT.executeQuery(strumrT);
						while (rsumrT.next()) {
							int householdid = Integer.parseInt(rsumrT.getString("householdid"));
							int movieid = Integer.parseInt(rsumrT.getString("movieid"));
							int rating = Integer.parseInt(rsumrT.getString("value"));
							Integer gTInv = gTMap.get(householdid);
							int mTInv = mTMap.get(movieid);
							gmRating[gTInv][mTInv] = rating;

						}
						
		} catch (Exception e) {
			System.out.print("get data error!");
			e.printStackTrace();
		}

		W = wordMap.size();
		Ug = usMap.size();
		Mu = mMap.size();
		

		System.out.println(M + " documents");
		System.out.println(W + " word types");
		System.out.println(G + "groups");
		System.out.println(U + "users");
		System.out.println(Ug + "users of groups");
		System.out.println(Mu + "movies rated by users");
		System.out.println(Um + "users of groups who rated movies ");
	}

	@Override
	public void likelihood() {
		double llh = 0;
		for (int m = 0; m < M; m++) {
			for (int n = 0; n < movies[m].length; n++) {
				double mAa = 0;
				int w = movies[m][n];
				for (int z = 0; z < Z; z++) {
					mAa += ((nZW[z][w] + beta) / (nZ[z] + W * beta))
							* ((nMZ[m][z] + alpha) / (nM[m] + Z * alpha));
					if (mAa > 1) {
						System.out.println("nZWU: " + nZW[z][w] + ", nZU: "
								+ nZ[z]);
						System.out.println(mAa);
					}
				}

				llh += Math.log(mAa);
			}
		}
		// System.out.println("Log-Likelihood: " + llh);
		System.out.println(llh);
	}
}

